package cn.cdeden.resource.service.impl;

import cn.cdeden.common.core.utils.StringUtils;
import cn.cdeden.common.oss.enumd.OssBucketOneEnum;
import cn.cdeden.common.oss.enumd.OssModuleOperate;
import cn.cdeden.common.oss.enumd.OssModuleType;
import cn.cdeden.common.satoken.utils.LoginHelper;
import cn.cdeden.knowledge.api.domain.RemotePersonalTreeService;
import cn.cdeden.resource.api.OssUploadService;
import cn.cdeden.resource.api.RemoteFileService;
import cn.cdeden.resource.api.domain.*;
import cn.cdeden.resource.domain.domain.AppData;
import cn.cdeden.resource.domain.ocr.OcrContent;
import cn.cdeden.resource.domain.ocr.PdfToMarkdownParams;
import cn.cdeden.resource.domain.ocr.PdfToMarkdownResponse;
import cn.cdeden.resource.service.ISysOcrService;
import cn.cdeden.resource.unified.service.RemoteUploadFileFilter;
import cn.cdeden.resource.utils.FileUtil;
import cn.cdeden.system.api.RemoteConfigService;
import cn.cdeden.system.api.RemoteUserService;
import cn.cdeden.system.api.domain.vo.RemoteUserVo;
import cn.cdeden.system.api.model.LoginUser;
import cn.hutool.core.io.resource.InputStreamResource;
import cn.hutool.core.io.resource.MultiResource;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * TODO
 *
 * @author Administrator
 * @date 2024/12/31 10:00
 * @describe:
 **/
@RequiredArgsConstructor
@Service
@Slf4j
public class SysOcrServiceImpl implements ISysOcrService {

    @DubboReference(check = false)
    private final RemoteConfigService remoteConfigService;

    private final RemoteUploadFileFilter personal;

    private final RemoteUploadFileFilter enterprise;

    @DubboReference(check = false)
    private final RemoteFileService remoteFileService;

    @DubboReference(check = false)
    private final RemoteUserService userService;


    /**
     * 获取OCR的选择
     *
     * @return
     */
    @Override
    public String getOcrResult() {
        String s = remoteConfigService.selectConfigByKey("ocr.choose");
        if (StringUtils.isNullOrBlank(s)) {
            return "";
        } else {
            return s;
        }
    }

    private AppData getAppData() {
        String appId = remoteConfigService.selectConfigByKey("apiOcr.appId");
        String appSecret = remoteConfigService.selectConfigByKey("apiOcr.appSecret");
        String baseUrl = remoteConfigService.selectConfigByKey("apiOcr.baseUrl");
        return new AppData(appId, appSecret,baseUrl);
    }

    //上传文件到OCR服务，并获取结果
    @Override
    public Map upload(MultipartFile pdfFile) {
        String ocrResult = getOcrResult();
        HashMap<String, String> map = new HashMap<>();
        RemoteFileDto build = null;
        try {
             build = RemoteFileDto.builder().file(pdfFile.getBytes())
                .moduleType(OssModuleType.Temporary)
                 .bucketName(OssBucketOneEnum.TEMPORARY_FILES.getCode())
                 .originalFilename(pdfFile.getOriginalFilename())
                 .contentType(pdfFile.getContentType())
                 .build();
        }catch (IOException e) {
            throw new RuntimeException(e);
        }
        RemoteFile upload = remoteFileService.upload(build);
        if (ocrResult.equals("Api")) {
            PdfToMarkdownParams params = new PdfToMarkdownParams();
            params.setPageStart(0);
            params.setPageCount(10); // 设置为解析1000页
            params.setTableFlavor("md");
            params.setParseMode("scan"); // 设置为scan模式
            params.setDpi(144); // 分辨率设置为144 dpi
            params.setGetImage("both");
            try {
                byte[] pdfBytes = pdfFile.getBytes();
                PdfToMarkdownResponse response = convertPdfToMarkdown(pdfBytes, params);
                map.put("ocrResult",response.getResult().getMarkdown());
                map.put("storageId",upload.getOssId().toString());
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else if (ocrResult.equals("MinerU")) {
            String originalFilename = pdfFile.getOriginalFilename();
            String suffix = FileUtil.getSuffix(originalFilename);
            String paddleUrlValue = getPaddleUrlValue();
            if (!StringUtils.isBlank(paddleUrlValue)&&(suffix.equals("png")||suffix.equals("jpg"))){
                String url = paddleUrlValue + "/ocr";
                MultiResource multiResource = null;
                String string = "";
                try {
                    multiResource = new MultiResource(new InputStreamResource(pdfFile.getInputStream(),pdfFile.getOriginalFilename()));
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                HttpResponse execute = cn.hutool.http.HttpRequest.post(url)
                    .form("file", multiResource)
                    .execute();
                int status = execute.getStatus();
                if (status == 200){
                    String body = execute.body();
                    String text = JSONObject.parseObject(body).getString("text");
                    List<String> strings = JSONObject.parseArray(text, String.class);
                    for (String s : strings) {
                        string += s + "\n\n";
                    }
                    map.put("ocrResult", string);
                    map.put("storageId", upload.getOssId().toString());
                }
            }else {
                String url = "";
                //上传pdf
                url = getOcrUrlValue() + "/pdf_parse";
                MultiResource multiResource = null;
                try {
                    multiResource = new MultiResource(new InputStreamResource(pdfFile.getInputStream(), pdfFile.getOriginalFilename()));
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                HttpResponse execute = cn.hutool.http.HttpRequest.post(url)
                    .form("pdf_file", multiResource)
                    .form("parse_method", "auto")
                    .form("is_json_md_dump", "true")
                    .form("output_dir", "/root/output").timeout(1000 * 60 * 5)
                    .execute();
                String body = execute.body();
                String string = JSONObject.parseObject(body).getString("md_content");

                map.put("ocrResult", string);
                map.put("storageId", upload.getOssId().toString());
            }
        } else {
            throw new RuntimeException("未配置OCR");
        }
        return map;
    }

    private String getOcrUrlValue(){
        return remoteConfigService.selectConfigByKey("minerU.baseUrl");
    }


    private String getPaddleUrlValue(){
        return remoteConfigService.selectConfigByKey("paddle.baseUrl");
    }

    private String minerUOCR(MultipartFile file) {
        String url = "";
        //上传pdf
        url = getOcrUrlValue() + "/api/v2/analysis/upload_pdf";
        MultiResource multiResource = null;
        try {
            multiResource = new MultiResource(new InputStreamResource(file.getInputStream(),file.getOriginalFilename()));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        HttpResponse execute = cn.hutool.http.HttpRequest.post(url)
            .form("file", multiResource)
            .execute();
        //解析返回
        String body = execute.body();
        String string = JSONObject.parseObject(body).getString("code");
        String msg = JSONObject.parseObject(body).getString("msg");
        if (string.equals("400")){
            throw new RuntimeException(msg);
        } else if (string.equals("200")) {
            String data = JSONObject.parseObject(body).getString("data");
            String file_key = JSONObject.parseObject(data).getString("file_key");

            //提交解析任务
            String taskUrl = getOcrUrlValue() + "/api/v2/extract/task/submit";
            HashMap<String, Object> hashMap = new HashMap<>();
            hashMap.put("fileKey", file_key);
            hashMap.put("taskType", "pdf");
            hashMap.put("isOcr",true);
            String post = HttpRequest.post(taskUrl).contentType("application/json").body(JSONObject.toJSONString(hashMap)).execute().body();
            String data1 = JSONObject.parseObject(post).getString("data");
            String id = JSONObject.parseObject(data1).getString("id");
            return id;
        }else {
            return null;
        }
    }

    @Override
    public HashMap<String, String> getStatus(Long id) {
        String ocrUrlValue = getOcrUrlValue();
        String url = ocrUrlValue + "/api/v2/extract/task/progress?id="+id;
        HttpResponse execute = HttpRequest.get(url).execute();
        String body = execute.body();
        JSONObject jsonObject = JSONObject.parseObject(body);
        JSONObject data = jsonObject.getJSONObject("data");

        String state = data.getString("state");
        HashMap<String, String> map = new HashMap<>();
        map.put("status", state);
        if(!StringUtils.isNullOrBlank(state)&&state.equals("done")){
            //提取文本
//            String fileName = FileUtil.getFileNameNoEx(JSONObject.parseObject(data).get("fileName").toString());
            String fullMdLink = data.getString("fullMdLink");
            HttpResponse execute1 = HttpRequest.get(fullMdLink).execute();
            String body1 = execute1.body();
            map.put("fullMdLink", fullMdLink);
            map.put("ocrResult",body1);
        }
        return map;
    }

    public PdfToMarkdownResponse convertPdfToMarkdown(byte[] pdfFile, PdfToMarkdownParams params) {
        // 使用restTemplate
        RestTemplate restTemplate = new RestTemplate();
        AppData appData = getAppData();
        // 构造请求头
        HttpHeaders headers = new HttpHeaders();
        headers.set("x-ti-app-id", appData.getAppId());
        headers.set("x-ti-secret-code", appData.getSecretCode());
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);

        // 构造url
        String url = buildUrl(params);
        log.info(url);

        // 发送请求
        HttpEntity<byte[]> requestEntity = new HttpEntity<>(pdfFile, headers);
        ResponseEntity<PdfToMarkdownResponse> response = restTemplate.exchange(
            url,
            HttpMethod.POST,
            requestEntity,
            PdfToMarkdownResponse.class
        );
        log.info(response.getBody().toString());

        return response.getBody();
    }

    public void main(String[] args) throws IOException {

        String filePath = "/home/file/example.pdf";
        File pdfFile = new File(filePath);


    }

    private String buildUrl(PdfToMarkdownParams params) {
        AppData appData = getAppData();
        UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(appData.getBaseUrl());
        if (params.getPdfPwd() != null) {
            uriBuilder.queryParam("pdf_pwd", params.getPdfPwd());
        }
        if (params.getDpi() != null) {
            uriBuilder.queryParam("dpi", params.getDpi());
        }
        if (params.getPageStart() != null) {
            uriBuilder.queryParam("page_start", params.getPageStart());
        }
        if (params.getPageCount() != null) {
            uriBuilder.queryParam("page_count", params.getPageCount());
        }
        if (params.getApplyDocumentTree() != null) {
            uriBuilder.queryParam("apply_document_tree", params.getApplyDocumentTree());
        }
        if (params.getMarkdownDetails() != null) {
            uriBuilder.queryParam("markdown_details", params.getMarkdownDetails());
        }
        if (params.getTableFlavor() != null) {
            uriBuilder.queryParam("table_flavor", params.getTableFlavor());
        }
        if (params.getGetImage() != null) {
            uriBuilder.queryParam("get_image", params.getGetImage());
        }
        if (params.getParseMode() != null) {
            uriBuilder.queryParam("parse_mode", params.getParseMode());
        }
        return uriBuilder.build().toUriString();
    }

    public void toLibrary(OcrContent ocrContent){
        String type = ocrContent.getType();
        LoginUser loginUser = LoginHelper.getLoginUser();
        File md = FileUtil.stringToFile(ocrContent.getRealName(), "md", ocrContent.getContent());
        FileInputStream fileInputStream = null;
        byte[] data =null;
        try {
            fileInputStream = new FileInputStream(md);
            data = new byte[(int) md.length()];
            fileInputStream.read(data);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                fileInputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        RemoteUserVo remoteUserVo = userService.selectUserByUserId(loginUser.getUserId());
        RemoteFileDto build = RemoteFileDto.builder().file(data)
            .bucketName(remoteUserVo.getMinioBucket())
            .originalFilename(ocrContent.getRealName()+".md")
            .contentType("text/markdown")
            .build();
        if (type.equals("personal")){
            build.setModuleType(OssModuleType.Personal);
            RemoteFile upload = remoteFileService.upload(build);

            RemoteFilesUpload buildUpload = RemoteFilesUpload.builder()
                .storageId(String.valueOf(upload.getOssId()))
                .fileSize(upload.getFileSize())
                .fileSuffix(upload.getFileSuffix())
                .type(OssModuleType.Personal.getCode())
                .fileName(upload.getOriginalName())
                .parentId(ocrContent.getTreeNodeId())
                .build();

            personal.upload(buildUpload,loginUser.getUserId(),OssModuleType.Personal.getCode());
            md.delete();
        } else if (type.equals("enterprise")) {
            RemoteFile remoteFile = remoteFileService.selectById(ocrContent.getStorageId());
            RemoteFilesUpload buildUpload = RemoteFilesUpload.builder()
                .storageId(ocrContent.getStorageId())
                .fileSize(remoteFile.getFileSize())
                .fileSuffix(remoteFile.getFileSuffix())
                .type(OssModuleType.Enterprise.getCode())
                .fileName(ocrContent.getRealName())
                .parentId(ocrContent.getTreeNodeId())
                .info(ocrContent.getInfo())
                .operate(OssModuleOperate.Ocr)
                .data(data)
                .build();
            enterprise.upload(buildUpload, loginUser.getUserId(), OssModuleType.Enterprise.getCode());
            md.delete();
        }
    }
}
